(* ::Package:: *)

(************************************************************************)
(* This file was generated automatically by the Mathematica front end.  *)
(* It contains Initialization cells from a Notebook file, which         *)
(* typically will have the same name as this file except ending in      *)
(* ".nb" instead of ".m".                                               *)
(*                                                                      *)
(* This file is intended to be loaded into the Mathematica kernel using *)
(* the package loading commands Get or Needs.  Doing so is equivalent   *)
(* to using the Evaluate Initialization Cells menu command in the front *)
(* end.                                                                 *)
(*                                                                      *)
(* DO NOT EDIT THIS FILE.  This entire file is regenerated              *)
(* automatically each time the parent Notebook file is saved in the     *)
(* Mathematica front end.  Any changes you make to this file will be    *)
(* overwritten.                                                         *)
(************************************************************************)



(*DataAcquisition.m --A package for calling C functions that control a National Instruments data acquisition card *)

BeginPackage["DAQ`DataAcquisition`"]


(* ::Subtitle::Closed:: *)
(*Usage strings and default options:*)


DataAcquisition::usage="DataAcquisition is a package that calls mathlinked C commands for a National Instruments data acquisition card. Functions are available for both input and output. They include GetVoltages, GetVoltagesTrig, GetVoltagesDigTrig, OutputVoltage, and OutputWaveform."
GetVoltages::usage="GetVoltages[channel list, sampling frequency, number of samples per channel] is a function that returns a list of voltages as read by the NIDAQ card. The channel must be a one dimensional list, frequency a real number, and number of samples an integer."
Options[GetVoltages]={Global`Device->1,Global`TerminalMode->Global`Differential,Global`MinValue->-10,Global`MaxValue->10,Global`Units->Global`Volts,Global`ClockSource->Global`OnboardClock,Global`ActiveEdge->Global`Rising,Global`SampleMode->Global`Finite,Global`TimeOut->10,Global`MessageLevel->0,Global`IncludeTime->Global`Include,Global`SetupOnly->False,Global`TransferMechanism->Global`Interrupts};
GetVoltagesTrig::usage="GetVoltagesTrig[channel list, sampling frequency, number of samples per channel,trig channel,trigger level] is a function that records voltages on input channels at specified frequency after receiving an analog trigger of correct magnitude on trigger channel. The channel list must be a one dimensional list, frequency a real number,number of samples an integer, trigchannel an integer, and trig level a real number."
Options[GetVoltagesTrig]={Global`Device->1,Global`TerminalMode->Global`Differential,Global`MinValue->-10,Global`MaxValue->10,Global`Units->Global`Volts,Global`ClockSource->Global`OnboardClock,Global`ActiveEdge->Global`Rising,Global`SampleMode->Global`Finite,Global`TimeOut->10,Global`TriggerSlope->Global`Rising,Global`PreTriggerSamples->0,Global`MessageLevel->0,Global`IncludeTime->Global`Include,Global`SetupOnly->False,Global`TransferMechanism->Global`Interrupts};
GetVoltagesDigTrig::usage="GetVoltagesDigTrig[channel list, sampling frequency, number of samples per channel,trigger channel] is a function that records voltages on input channels at specified frequency after receiving a digital edge on trigger channel. Channel list must be a one dimensional list, frequency a real number, number of samples an integer, and trigger channel an integer."
Options[GetVoltagesDigTrig]={Global`Device->1,Global`TerminalMode->Global`Differential,Global`MinValue->-10,Global`MaxValue->10,Global`Units->Global`Volts,Global`ClockSource->Global`OnboardClock,Global`ActiveEdge->Global`Rising,Global`SampleMode->Global`Finite,Global`TimeOut->10,Global`TriggerEdge->Global`Rising,Global`MessageLevel->0,Global`IncludeTime->Global`Include,Global`TriggerSlope->Global`Rising,Global`PreTriggerSamples->0,Global`SetupOnly->False,Global`TransferMechanism->Global`Interrupts};
OutputVoltage::usage="OutputVoltage[channel list, voltage] is a function that outputs voltage on the specified channels. The function returns an integer that can be used with ClearTask to stop the task. The channel list must be one dimensional, and voltage must be a real number."
Options[OutputVoltage]={Global`Device->1,Global`MinValue->-10,Global`MaxValue->10,Global`Units->Global`Volts,Global`TimeOut->10,Global`MessageLevel->0,Global`SetupOnly->False,Global`TransferMechanism->Global`Interrupts,Global`ClockSource->Global`OnboardClock}
OutputWaveform::usage="OutputWaveform[channel list, waveform, frequency of point output, number of periods] is a function that outputs the waveform list as voltages on listed channels at specified frequency for a certain number of periods. The function returns an integer that can be used with ClearTask to stop the output. For continuous output use the option SampleMode->Continuous. The channel list must be one dimensional, waveform a list of real numbers, frequency and number of periods must also be real numbers."
Options[OutputWaveform]={Global`Device->1,Global`MinValue->-10,Global`MaxValue->10,Global`Units->Global`Volts,Global`ClockSource->Global`OnboardClock,Global`ActiveEdge->Global`Rising,Global`TransferMechanism->Global`Interrupts,Global`SampleMode->Global`Finite,Global`TimeOut->10,Global`MessageLevel->0,Global`SetupOnly->False};
ReDoLink::usage="ReDoLink[] is a function that resets the Mathlink connection, or if no connection is currently open it establishes a connection."


Begin["`Private`"]


(* ::Subtitle::Closed:: *)
(*Message Statements*)


messages:=
(continuousmessage:="When using the SampleMode->Continous mode the number of periods argument is ignored but still required as input. To stop a continuous waveform output you must clear the task using the ClearTask command and your task number. (To suppress this message use the MessageLevel->#<2 option.)";
setuponlymessage:="When using the SetupOnly->True option you are returned an integer.  To complete the task use RunTask[] with that integer as an argument. That task is completed upon each evaluation of RunTask[].  You must clear the task using ClearTask[] with that integer as an argument in order to change the task.(To suppress this message use the MessageLevel->#<2 option.)";

If[outwaveflag===1&&messagelevel>1&&samplemode===Global`Continuous,Print[continuousmessage];,Null];
If[setupflag===1&&messagelevel>1,Print[setuponlymessage];,Null];

If[includetimeflag===1&&messagelevel>1&&setupflag===0,Print["Your units are {seconds,volts}."];,Null];
If[includetimeflag===0&&messagelevel>1&&setupflag===0,Print["Your units are {volts}."];,Null];);


(* ::Subtitle::Closed:: *)
(*Argument and Option tests*)


(* ::Subsubtitle:: *)
(*argumenttests and optiontests definitions*)


argumenttests:=(If[ValueQ[chan],samplechanneltest;,Null];
If[ValueQ[freq],frequencytest,Null];
If[ValueQ[samples],samplestest,Null];
If[ValueQ[trigchannel],triggerchanneltest,Null];
If[ValueQ[triglevel],triggerleveltest,Null];
If[ValueQ[wavechan],waveformchanneltest;waveformtest;,Null];
If[ValueQ[periods],periodstest,Null];);

optiontests:=(If[ValueQ[device],devicetest[device],Null];
If[ValueQ[terminalmode],terminaltest[terminalmode],Null];
If[ValueQ[minvalue]&&ValueQ[maxvalue],voltagetest[minvalue,maxvalue],Null];
If[ValueQ[units],unitstest[units],Null];
If[ValueQ[clocksource],clocksourcetest,Null];
If[ValueQ[activeedge],activeedgetest,Null];
If[ValueQ[samplemode],samplemodetest,Null];
If[ValueQ[timeout],timeouttest,Null];
If[ValueQ[messagelevel],messageleveltest];
If[ValueQ[includetime],includetimetest,Null];
If[ValueQ[triggerslope],triggerslopetest,Null];
If[ValueQ[pretriggersamples],pretriggertest,Null];
If[ValueQ[transfermechanism],transfermechanismtest,Null];
If[ValueQ[setuponly],setuptest,Null]);


(* ::Text:: *)
(*THE CHANNEL ARGUMENT*)


samplechanneltest:=(If[Head[chan]===List&&Depth[chan]===2,Null,error="Error: Channel list argument must be specified as a one dimensional list of integers.";Goto[clearandabort];];
If[Length[Select[chan,#>7&]]>0&&(terminalmode===Global`Differential||terminalmode===Global`DAQDefault),error="Error: Channel argument out of range (0 to 7) for Differential (or DAQDefault) terminal mode.";Goto[clearandabort];,Null];
If[Length[Select[chan,#>15&]]>0&&(terminalmode===Global`NonRSE||terminalmode===Global`RSE),error="Error: Channel list argument out of range (0 to 15) for single ended terminal mode.";Goto[clearandabort];,Null];
If[Length[Select[chan,IntegerQ]]<Length[chan]||Length[Select[chan,NonNegative]]<Length[chan],error="Error: The channel list argument must contain only non-negative integers.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE WAVEFORM CHANNEL ARGUMENT*)


waveformchanneltest:=(If[Head[wavechan]===List,Null,error="Error: Channel list argument must be a list.";Goto[clearandabort]];
If[Union[wavechan]==={0}||Union[wavechan]==={1}||Union[wavechan]==={0,1},Null,error="Error: The union of the channel argument must be one of the elements in the following list {{0},{1},{0,1}}.";Goto[clearandabort];];
If[outwaveflag===1&&(Length[Union[wavechan]]===1&&Depth[wave//N]=!=2),error="Error: When using a single channel, the waveform list must be one dimensional.";Goto[clearandabort];,Null];
If[outwaveflag===1&&(Length[Union[wavechan]]===2&&Depth[wave//N]=!=2&&Depth[wave//N]=!=3),error="Error: When using both channels the Waveform argument must be a list of depth 2 or 3 (either a one dimensional  list {} or a list of two one dimensional lists {{},{}}.";Goto[clearandabort];,Null];
If[outwaveflag===1&&(Head[wavechan]===List&&Length[Union[wavechan]]===2&&Depth[wave//N]===3&&(Length[wave[[1]]]=!=Length[wave[[2]]]||Length[wave]>2)),error="When both channels are used and the waveform argument is a list of two lists, the two elements of waveform must be of equal length.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE FREQUENCY ARGUMENT*)


frequencytest:=(If[Head[freq]=!=Symbol&&Element[freq,Reals]&&Positive[freq]&&freq<=140000,Null,error="Error: Frequency must be a positive real number less than or equal to 140,000.";Goto[clearandabort];];)


(* ::Text:: *)
(*THE NUMBER OF SAMPLES PER CHANNEL ARGUMENT*)


samplestest:=(If[Head[samples]=!=Symbol&&Element[samples,Integers]&&Positive[samples]&&samples<=100000,Null,error="Error: Number of Samples argument must be a positive integer less than or equal to 100,000.";Goto[clearandabort];];)


(* ::Text:: *)
(*THE TRIGGER LEVEL ARGUMENT*)


triggerleveltest:=(If[(minvalue<=triglevel<=maxvalue)&&Element[triglevel,Reals]&&Head[triglevel]=!=Symbol,Null,error="Error: Trigger level must be a real number between MinValue and MaxValue";Goto[clearandabort];];)


(* ::Text:: *)
(*THE TRIGGER CHANNEL ARGUMENT*)


triggerchanneltest:=(If[Head[trigchannel]===Integer&&trigchannel>=0&&trigchannel<=9,Null,error="Error: Trigger channel argument must be an integer in the range (inclusive) 0 to 9.";Goto[clearandabort];];)


(* ::Text:: *)
(*THE WAVEFORM ARGUMENT*)


waveformtest:=(If[Head[wave]===List,Null,error="Error:The Waveform argument must be a list.";Goto[clearandabort];];
If[outputflag===1&&(!Element[wave[[1]],Reals]||wave[[1]]<minvalue||wave[[1]]>maxvalue),error="Error:The voltage argument must be a real number between MinValue and MaxValue (defaults are-10 and+10 respectively).";Goto[clearandabort];,Null];
If[outputflag===1&&Head[wave[[1]]//N]=!=Real,error="Error:The voltage argument must be a real number.";Goto[clearandabort];,Null];
If[Length[Select[Join[Flatten[wave]],realtest]]<Length[Join[Flatten[wave]]],error="Error:All of the elements of the argument Waveform (list) must be real numbers.";Goto[clearandabort];];
If[Length[Select[Join[Flatten[wave]],#>maxvalue&]]>0||Length[Select[Join[Flatten[wave]],#<minvalue&]]>0,error="Error: All elements of the Waveform argument list must be within the range of MinValue to MaxValue (defaults are -10 and +10 respectively).";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE NUMBER OF PERIODS ARGUMENT*)


periodstest:=(If[(!Element[periods,Reals]||!(periods>0)||Head[periods]===Symbol)&&samplemode===Global`Finite,error="Error: Number of periods argument must be a positive real number.";Goto[clearandabort];,Null];);


(* ::Text:: *)
(*THE DEVICE OPTION*)


devicetest:=(If[Element[device,Integers]&&device>=0&&Head[device]=!=Symbol,Null,error="Error: Device must be specified as an integer greater than or equal to zero.";Goto[clearandabort];];);


(* ::Text:: *)
(*THE TERMINAL MODE OPTION*)


terminaltest:=(If[Head[terminalmode]=!=Symbol||(Head[terminalmode]===Symbol&&terminalmode=!=Global`Differential&&terminalmode=!=Global`RSE&&terminalmode=!=Global`NonRSE&&terminalmode=!=Global`DAQDefault),error="Error: Terminal Mode was not specified as DAQDefault,Differential, RSE, or NonRSE.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE MINVALUE AND MAXVALUE OPTIONS*)


voltagetest:=(If[minvalue>=-10&&Element[minvalue,Reals],Null,error="Error: MinValue should be a real number greater than or equal to -10 when using Units->Volts (default).";Goto[clearandabort];];
If[maxvalue<=10&&Element[maxvalue,Reals],Null,error="Error: MaxValue should be a real number less than or equal to 10 when using Units->Volts (default).";Goto[clearandabort];];
If[maxvalue>minvalue,Null,error="Error: MaxValue should be greater than MinValue";Goto[clearandabort];];
If[Head[minvalue]===Symbol||Head[maxvalue]===Symbol,error="Error: MinValue and MaxValue must be specified as real numbers.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE UNITS OPTION*)


unitstest:=(If[Head[units]=!=Symbol||(Head[units]===Symbol&&units=!=Global`Volts&&Units=!=Global`CustomScale),error="Error: Units was not specified as Volts or CustomScale.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE CLOCK SOURCE OPTION*)


clocksourcetest:=(If[Head[clocksource]=!=Symbol||(clocksource=!=Global`OnboardClock),error="Error: ClockSource should be OnboardClock.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE ACTIVE EDGE OPTION*)


activeedgetest:=(If[Head[activeedge]=!=Symbol||(Head[activeedge]===Symbol&&activeedge=!=Global`Rising&&activeedge=!=Global`Falling),error="Error: Active Edge was not specified as Rising or Falling.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE SAMPLE MODE OPTION*)


samplemodetest:=(If[Head[samplemode]=!=Symbol||(Head[samplemode]===Symbol&&samplemode=!=Global`Finite&&samplemode=!=Global`Continuous),error="Error: SampleMode was not specified as Finite or Continuous.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE TIME OUT OPTION*)


timeouttest:=(If[(!Element[timeout,Reals]||!Positive[timeout])||(Head[timeout]===Symbol&&timeout=!=Global`WaitForever),error="Error: TimeOut needs to be a positive real number or WaitForever.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE MESSAGE LEVEL OPTION*)


messageleveltest:=(If[Head[messagelevel]=!=Symbol&&MemberQ[{0,1,2,3,4,5},messagelevel],Null,error="Error: MessageLevel option was not specified as 0,1,2,3,4,or 5.";Goto[clearandabort];];)


(* ::Text:: *)
(*THE INCLUDE TIME OPTION*)


includetimetest:=(If[Head[includetime]===Symbol&&includetime=!=Global`Include&&includetime=!=Global`Omit,error="Error: IncludeTime option was not specified as Omit or Include.";Goto[clearandabort];,Null];
If[includetime===Global`Include,includetimeflag=1,includetimeflag=0];)


(* ::Text:: *)
(*THE TRIGGER SLOPE OPTION*)


triggerslopetest:=(If[Head[triggerslope]=!=Symbol||(Head[triggerslope]===Symbol&&triggerslope=!=Global`Rising&&triggerslope=!=Global`Falling),error="Error: TriggerSlope option was not specified as Rising or Falling.";Goto[clearandabort];,Null];)


(* ::Text:: *)
(*THE TRANSFER MECHANISM OPTION*)


transfermechanismtest:=(
If[Head[transfermechanism]=!=Symbol||(Head[transfermechanism]===Symbol&&transfermechanism=!=Global`Interrupts&&transfermechanism=!=Global`DMA),error="Error: TransferMechanism option was not specified as Interrupts or DMA.";Goto[clearandabort];,Null];)



(* ::Text:: *)
(*THE PRE TRIGGER SAMPLES OPTION*)


pretriggertest:=(If[Head[pretriggersamples]=!=Symbol&&Element[pretriggersamples,Reals]&&pretriggersamples>=0,Null,error="Error: PreTriggerSamples option must be specified (ruled) as a real number greater than or equal to zero.";Goto[clearandabort];];
If[Element[pretriggersamples,Integers]&&(pretriggersamples+samples<=100000),Null,error="Error: The sum of the PreTriggerSamples option specification and the number of samples argument must be an integer less than or equal to 100,000.";Goto[clearandabort];];)


(* ::Text:: *)
(*THE SETUP ONLY OPTION*)


setuptest:=(If[setuponly===True||setuponly===False,Null,error="The SetupOnly option was not specified as True or False";Goto[ clearandabort];];
If[setuponly===True,setupflag=1,setupflag=0];);


(* ::Subtitle::Closed:: *)
(*Delayed Assignments for main functions*)


setconstants:=(
Global`DAQDefault=0;
Global`RSE=1;
Global`NonRSE=2;
Global`Differential=3;
Global`Rising=0;
Global`Falling=1;
Global`Volts=0;
Global`CustomScale=1;
Global`Finite=0;
Global`Continuous=1;
Global`WaitForever=-1;
Global`Omit=0;
Global`Include=1;
Global`Interrupts=0;
Global`DMA=1;); 
clearconstants:=Clear[
Global`DAQDefault,
Global`RSE,
Global`NonRSE,
Global`Differential,
Global`Rising,
Global`Falling,
Global`Volts,
Global`CustomScale,
Global`Finite,
Global`Continuous,
Global`WaitForever,
Global`Omit,
Global`Include,
Global`Interrupts,
Global`DMA,
outwaveflag,outputflag,includetimeflag,
error,device,samplemode,terminalmode,minvalue,maxvalue,units,clocksource,activeedge,timeout,messagelevel,includetime,triggerslope,pretriggersamples,trigchannel,triglevel,wave,setupflag,transfermechanism,setuponly,wavechan,freq,periods,chan,samples];
UnsortedUnion[x_]:=Module[{f},f[y_]:=(f[y]=Sequence[];y);f/@x];
getinputdevicestring:=(devicestring=StringDrop[StringDrop[ToString[ToString[Table["dev"<>ToString[device]<>"/ai"<>ToString[UnsortedUnion[chan][[n]]],{n,1,numberofchannels}]]],1],-1];)
getoutputdevicestring:=(devicestring=StringDrop[StringDrop[ToString[ToString[Table["dev"<>ToString[device]<>"/ao"<>ToString[UnsortedUnion[wavechan][[n]]],{n,1,numberofchannels}]]],1],-1];);
getnumberofchannels:=(If[outwaveflag===1||outputflag===1,numberofchannels=Length[Union[wavechan]];,numberofchannels=Length[Union[chan]]];);
getpostimelist:=(
If[Head[listfromcall]===Integer, Return[listfromcall]]; (* return taskHandle *)
postimelist=Map[N,Table[i,{i,0,(samples-1)/freq,(1/freq)}]]);
getnegtimelist:=(
If[Head[listfromcall]===Integer, Return[listfromcall]]; (* return taskHandle *)
negtimelist=Map[N,Table[i,{i,-(Length[listfromcall[[1]]]/numberofchannels)/freq,0-(1/freq),(1/freq)}]]);
getcompletelist:=(
If[Head[listfromcall]===Integer, Return[listfromcall]]; (* return taskHandle *)
If[includetimeflag===1&&numberofsamples=!=1,newlist=Table[Transpose[{postimelist,Take[listfromcall,{n,-1,numberofchannels}]}],{n,1,numberofchannels}];,newlist=Table[Take[listfromcall,{n,-1,numberofchannels}],{n,1,numberofchannels}];]);
gettrigcompletelist:=(
If[Head[listfromcall]===Integer, Return[listfromcall]]; (* return taskHandle *)
timeslist=Join[negtimelist,postimelist];
longlist=Join[listfromcall[[1]],listfromcall[[2]]];
If[includetimeflag===1&&numberofsamples=!=1,newlist=Table[Transpose[{timeslist,Take[longlist,{n,-1,numberofchannels}]}],{n,1,numberofchannels}];,newlist=Table[Take[longlist,{n,-1,numberofchannels}],{n,1,numberofchannels}]]);
checksetuponly:=(
(* This function needs to be changed to allowing for skipping following commands
Print["head is :",Head[listfromcall]]; *)
If[Head[listfromcall]===Integer,clearconstants;Return[listfromcall],Null]);
getnewlistfromcall:=(
(* Print["Setup only is",setuponly,"numchannels is: ",numberofchannels ]; *)
If[Head[listfromcall]===Integer, Return[newlistfromcall=listfromcall]]; (* return taskHandle *)
If[numberofchannels===1,newlistfromcall=Flatten[newlist,1],newlistfromcall=newlist];
newlistfromcall);
realtest[x_]:=Simplify[x\[Element]Reals];


(* ::Subtitle:: *)
(*Links and Aborts*)


(* ============== INSTALL AND REINSTALL LINK DEFINITIONS ======== *)
(* working directory set to location of desired executable *)
(* for the momment put exe and package together and set directory to that spot
	to make distribution simple probably should be a switch  *)

If[ValueQ[Global`DAQTesting],
Print["Testing...using current directory"];,
SetDirectory[StringJoin[$InstallationDirectory,"\\AddOns\\ExtraPackages\\DAQ"]];
];
Print[Directory[]];

DAQlink="mathDAQ";
(* test not working as linkobject returned *)
ReDoLink[]:=If[MemberQ[Links[],DAQlink],Uninstall[DAQlink];Install[DAQlink];,Install[DAQlink];];
ReDoLink[];
If[ValueQ[Global`DAQTesting],Null;,ResetDirectory[];];

(* ========== END INSTALL AND REINSTALL LINK DEFINITIONS ======== *)

(*clear the constants so if we call Options[] after calling a function (error or not), the rules still appear as symbols and not numerically, putting this label outside the function definitions only works because this is a saved initiallization cell*)

Label[linkabort];
linkabort:=(clearconstants;
Abort[];);

Label[clearandabort];
clearandabort:=
(If[messagelevel===0,Null,Print[error]];
clearconstants;
Abort[];);


(* ::Subtitle:: *)
(*Main Function Definitions*)


(* ::Subsubtitle:: *)
(*	GetVoltages*)


(*============ GetVoltages Definition Section ===========*)

GetVoltages::badarg="GetVoltages must be called with 3 arguments."

GetVoltages[channel_,frequency_,numberofsamples_,opts___Rule]:=
(clearconstants;
chan=channel;
freq=frequency;
samples=numberofsamples;

optionlist={Global`Device,Global`TerminalMode,Global`MinValue,Global`MaxValue,Global`Units,Global`ClockSource,Global`ActiveEdge,Global`SampleMode,Global`TimeOut,Global`MessageLevel,Global`IncludeTime,Global`SetupOnly,Global`TransferMechanism}/.Flatten[{opts,Options[GetVoltages]}];
golocal={device,terminalmode,minvalue,maxvalue,units,clocksource,activeedge,samplemode,timeout,messagelevel,includetime,setuponly,transfermechanism};
Apply[Set,Transpose[{golocal,optionlist}],1];

argumenttests;
optiontests;
setconstants;
getnumberofchannels;
getinputdevicestring;

listforcall={{"channels",devicestring},{"numchannels",numberofchannels},{"frequency",N[freq]},{"samples",samples},{"terminalmode",terminalmode},{"min",N[minvalue]},{"max",N[maxvalue]},{"units",units},{"clock",ToString[clocksource]},{"activeedge",activeedge},{"samplemode",0},{"timeout",N[timeout]},{"messagelevel",messagelevel},{"setuponly",setupflag},{"transfermech",transfermechanism}};
listfromcall=CheckAbort[Global`GetVoltagesCpp[listforcall],LinkInterrupt[DAQlink];Goto[linkabort]];

(* Fix me control flow problem -- checksetuponly shound skip the following functions *)
checksetuponly;
getpostimelist;
getcompletelist;
messages;
clearconstants;
getnewlistfromcall;
Return[newlistfromcall])

GetVoltages[arg__/;Length[{arg}]<3||Length[{arg}]>3]:=Message[GetVoltages::badarg,{arg}];
(*=============== END GETVOLTAGES DEFINITION ===============*)


(* ::Subsubtitle:: *)
(*	GetVoltagesTrig*)


(*==== GetVoltagesTrig Definition Section =====*)

GetVoltagesTrig::badarg="GetVoltagesTrig must be called with 5 arguments."

GetVoltagesTrig[channel_,frequency_,numberofsamples_,triggerchannel_,triggerlevel_,opts___Rule]:=(clearconstants;
chan=channel;
freq=frequency;
samples=numberofsamples;
trigchannel=triggerchannel;
triglevel=triggerlevel;

optionlist={Global`Device,Global`TerminalMode,Global`MinValue,Global`MaxValue,Global`Units,Global`ClockSource,Global`ActiveEdge,Global`SampleMode,Global`TimeOut,Global`TriggerSlope,Global`PreTriggerSamples,Global`MessageLevel,Global`IncludeTime,Global`SetupOnly,Global`TransferMechanism}/.Flatten[{opts,Options[GetVoltagesTrig]}];
golocal={device,terminalmode,minvalue,maxvalue,units,clocksource,activeedge,samplemode,timeout,triggerslope,pretriggersamples,messagelevel,includetime,setuponly,transfermechanism};
Apply[Set,Transpose[{golocal,optionlist}],1];

argumenttests;
optiontests;
setconstants;
getnumberofchannels;
getinputdevicestring;
sourcestring:="PFI"<>ToString[trigchannel];

listforcall={{"channels",devicestring},{"numchannels",numberofchannels},{"frequency",N[freq]},{"pretrigsamples",pretriggersamples},{"posttrigsamples",samples},{"samples",pretriggersamples},{"terminalmode",terminalmode},{"min",N[minvalue]},{"max",N[maxvalue]},{"units",units},{"clock",ToString[clocksource]},{"activeedge",activeedge},{"samplemode",1},{"timeout",N[timeout]},{"messagelevel",messagelevel},{"triggersource",sourcestring},{"triggerslope",triggerslope},{"triggerlevel",N[triglevel]},{"transfermech",transfermechanism},{"setuponly",setupflag}};
listfromcall=CheckAbort[Global`GetVoltagesSoftwareTrig[listforcall],LinkInterrupt[DAQlink];Goto[linkabort];];

checksetuponly;
getpostimelist;
getnegtimelist;
gettrigcompletelist;

messages;
clearconstants;

getnewlistfromcall;
Return[newlistfromcall])

GetVoltagesTrig[arg__/;Length[{arg}]<5||Length[{arg}]>5]:=Message[GetVoltagesTrig::badarg,{arg}];
(*==== END GetVoltagesTrig Definition Section =====*)



(* ::Subsubtitle:: *)
(*	GetVoltagesDigTrig*)


(*======= GetVoltagesDigTrig Definition Section ====*)

GetVoltagesDigTrig::badarg="GetVoltagesDigTrig must be called with 4 arguments."

GetVoltagesDigTrig[channel_,frequency_,numberofsamples_,triggerchannel_,opts___Rule]:=
(clearconstants;
chan=channel;
freq=frequency;
samples=numberofsamples;
trigchannel=triggerchannel;

optionlist={Global`Device,Global`TerminalMode,Global`MinValue,Global`MaxValue,Global`Units,Global`ClockSource,Global`ActiveEdge,Global`SampleMode,Global`TimeOut,Global`MessageLevel,Global`IncludeTime,Global`TriggerSlope,Global`PreTriggerSamples,Global`SetupOnly,Global`TransferMechanism}/.Flatten[{opts,Options[GetVoltagesDigTrig]}];
golocal={device,terminalmode,minvalue,maxvalue,units,clocksource,activeedge,samplemode,timeout,messagelevel,includetime,triggerslope,pretriggersamples,setuponly,transfermechanism};
Apply[Set,Transpose[{golocal,optionlist}],1];

argumenttests;
optiontests;
setconstants;
getnumberofchannels;
getinputdevicestring;
sourcestring:="PFI"<>ToString[trigchannel];

listforcall={{"channels",devicestring},{"numchannels",numberofchannels},{"frequency",N[freq]},{"terminalmode",terminalmode},{"min",N[minvalue]},{"max",N[maxvalue]},{"units",units},{"clock",ToString[clocksource]},{"activeedge",activeedge},{"samplemode",1},{"timeout",N[timeout]},{"messagelevel",messagelevel},{"triggersource",sourcestring},{"triggerslope",triggerslope},{"pretrigsamples",pretriggersamples},{"samples",pretriggersamples},{"posttrigsamples",samples},{"setuponly",setupflag},{"transfermech",transfermechanism}};
listfromcall=CheckAbort[Global`GetVoltagesDigitalTrig[listforcall],LinkInterrupt[DAQlink];Goto[linkabort];];

checksetuponly;
getpostimelist;
getnegtimelist;
gettrigcompletelist;
messages;
clearconstants;
getnewlistfromcall;
Return[newlistfromcall])

GetVoltagesDigTrig[arg__/;Length[{arg}]<4||Length[{arg}]>4]:=Message[GetVoltagesDigTrig::badarg,{arg}];

(*==== END GetVoltagesDigTrig Definition Section =====*)



(* ::Subsubtitle:: *)
(*	OutputVoltage*)


(*==== OutputVoltage Definition Section =====*)
(*==== Note: OutputVoltage calls OutputWaveformCpp =====*)
OutputVoltage::badarg="OutputVoltage must be called with 2 arguments."

OutputVoltage[channel_,voltage_,opts___Rule]:=
(clearconstants;
wavechan=channel;
wave={voltage};
outputflag=1;
optionlist:={Global`Device,Global`MinValue,Global`MaxValue,Global`Units,Global`TimeOut,Global`MessageLevel,Global`SetupOnly,Global`TransferMechanism}/.Flatten[{opts,Options[OutputVoltage]}];
golocal={device,minvalue,maxvalue,units,timeout,messagelevel,setuponly,transfermechanism};
Apply[Set,Transpose[{golocal,optionlist}],1];

argumenttests;
optiontests;
setconstants;
getnumberofchannels;
getoutputdevicestring;

If[numberofchannels===2,newwave=Join[wave,wave],newwave=wave];
listforcall={{"channels",devicestring},{"numchannels",numberofchannels},{"waveform",newwave//N},{"frequency",N[1]},{"samples",1},{"numperiods",N[1]},{"min",N[minvalue]},{"max",N[maxvalue]},{"units",units},{"transfermech",transfermechanism},{"clock","OnboardClock"},{"activeedge",0},{"samplemode",0},{"timeout",N[timeout]},{"messagelevel",messagelevel},{"setuponly",setupflag}};
taskhandle=CheckAbort[Global`OutputWaveformCpp[listforcall],LinkInterrupt[DAQlink];Goto[linkabort];];

messages;
clearconstants;
Return[taskhandle])

OutputVoltage[arg__/;Length[{arg}]<2||Length[{arg}]>2]:=Message[OutputVoltage::badarg,{arg}];

(*=========== End OutputVoltage Definition Section ===========*)



(* ::Subsubtitle:: *)
(*	OutputWaveform*)


(*=========== OutputWaveform Definition Section ===========*)

OutputWaveform::badarg="OutputWaveform must be called with 4 arguments."

OutputWaveform[channel_,waveform_,frequency_,numberofperiods_,opts___Rule]:=
(clearconstants;
wavechan=channel;
wave=waveform;
freq=frequency;
periods=numberofperiods;

optionlist:={Global`Device,Global`MinValue,Global`MaxValue,Global`Units,Global`ClockSource,Global`ActiveEdge,Global`TransferMechanism,Global`SampleMode,Global`TimeOut,Global`MessageLevel,Global`SetupOnly}/.Flatten[{opts,Options[OutputWaveform]}];
golocal={device,minvalue,maxvalue,units,clocksource,activeedge,transfermechanism,samplemode,timeout,messagelevel,setuponly};
Apply[Set,Transpose[{golocal,optionlist}],1];

outwaveflag=1;
argumenttests;
optiontests;
setconstants;
getnumberofchannels;
getoutputdevicestring;

If[numberofchannels===1,samples=Length[wave];newwave=wave;,Null];
If[numberofchannels===2&&Depth[wave//N]===2,samples=Length[wave];newwave=Join[wave,wave];,Null];
If[numberofchannels===2&&Depth[wave//N]===3,samples=Length[wave[[1]]];newwave=Join[wave[[1]],wave[[2]]];,Null];

listforcall={{"channels",devicestring},{"numchannels",numberofchannels},{"waveform",newwave//N},{"frequency",N[freq]},{"samples",samples},{"numperiods",N[periods]},{"min",N[minvalue]},{"max",N[maxvalue]},{"units",units},{"transfermech",transfermechanism},{"clock",ToString[clocksource]},{"activeedge",activeedge},{"samplemode",samplemode},{"timeout",N[timeout]},{"messagelevel",messagelevel},{"setuponly",setupflag}};
taskhandle=CheckAbort[Global`OutputWaveformCpp[listforcall],LinkInterrupt[outputwaveformlink];Goto[linkabort];];

messages;
clearconstants;
Return[taskhandle])

OutputWaveform[arg__/;Length[{arg}]<4||Length[{arg}]>4]:=Message[OutputWaveform::badarg,{arg}];

(*=========== End OutputWaveform Definition Section ===========*)


(* end private *)
End[];

Protect[GetVoltages,GetVoltagesTrig,GetVoltagesDigTrig,OutputVoltage,OutputWaveform,ReDoLink];

(* end package *)
EndPackage[];
